/*
 * Tencent is pleased to support the open source community by making Tinker available.
 *
 * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
 *
 * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 *
 * https://opensource.org/licenses/BSD-3-Clause
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.evamay.mytinkerdemo.utils

import android.os.Environment
import android.os.StatFs

import com.tencent.tinker.loader.shareutil.ShareConstants

import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import java.io.PrintStream

object Utils {

    /**
     * the error code define by myself
     * should after `ShareConstants.ERROR_PATCH_INSERVICE`
     */
    val ERROR_PATCH_GOOGLEPLAY_CHANNEL = -5
    val ERROR_PATCH_ROM_SPACE = -6
    val ERROR_PATCH_MEMORY_LIMIT = -7
    val ERROR_PATCH_ALREADY_APPLY = -8
    val ERROR_PATCH_CRASH_LIMIT = -9
    val ERROR_PATCH_RETRY_COUNT_LIMIT = -10
    val ERROR_PATCH_CONDITION_NOT_SATISFIED = -11

    val PLATFORM = "platform"

    val MIN_MEMORY_HEAP_SIZE = 45

    var isBackground = false

    val isGooglePlay: Boolean
        get() = false

    fun checkForPatchRecover(roomSize: Long, maxMemory: Int): Int {
        if (Utils.isGooglePlay) {
            return Utils.ERROR_PATCH_GOOGLEPLAY_CHANNEL
        }
        if (maxMemory < MIN_MEMORY_HEAP_SIZE) {
            return Utils.ERROR_PATCH_MEMORY_LIMIT
        }
        //or you can mention user to clean their rom space!
        return if (!checkRomSpaceEnough(roomSize)) {
            Utils.ERROR_PATCH_ROM_SPACE
        } else ShareConstants.ERROR_PATCH_OK

    }

    fun isXposedExists(thr: Throwable): Boolean {
        val stackTraces = thr.stackTrace
        for (stackTrace in stackTraces) {
            val clazzName = stackTrace.className
            if (clazzName != null && clazzName.contains("de.robv.android.xposed.XposedBridge")) {
                return true
            }
        }
        return false
    }

    @Deprecated("")
    fun checkRomSpaceEnough(limitSize: Long): Boolean {
        var allSize: Long
        var availableSize: Long = 0
        try {
            val data = Environment.getDataDirectory()
            val sf = StatFs(data.path)
            availableSize = sf.availableBlocks.toLong() * sf.blockSize.toLong()
            allSize = sf.blockCount.toLong() * sf.blockSize.toLong()
        } catch (e: Exception) {
            allSize = 0
        }

        return allSize != 0L && availableSize > limitSize
    }

    fun getExceptionCauseString(ex: Throwable): String? {
        val bos = ByteArrayOutputStream()
        val ps = PrintStream(bos)

        try {
            // print directly
            var t = ex
            while (t.cause != null) {
                t = t.cause!!
            }
            t.printStackTrace(ps)
            return toVisualString(bos.toString())
        } finally {
            try {
                bos.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
    }

    private fun toVisualString(src: String?): String? {
        var cutFlg = false

        if (null == src) {
            return null
        }

        val chr = src.toCharArray() ?: return null

        var i = 0
        while (i < chr.size) {
            if (chr[i].toInt() > 127) {
                chr[i] = 0.toChar()
                cutFlg = true
                break
            }
            i++
        }

        return if (cutFlg) {
            String(chr, 0, i)
        } else {
            src
        }
    }
}
